#include <device.h>
#include <stm32f0xx.h>
#include "stm32_spi.h"
#include "board.h"

#ifdef configUSING_SPI_BITBANG
/*
 * GPIO define
 * SPI1_MOSI: PB5
 * SPI1_MISO: PB4
 * SPI1_SCK : PB3
 * CS0: PA15
 */
#define GPIO_PORT_SPI_CS    GPIOA
#define RCC_SPI_CS          RCC_AHBPeriph_GPIOA
#define PIN_SPI_CS          GPIO_Pin_15

#define GPIO_PORT_SPI_SCK   GPIOB
#define RCC_SPI_SCK         RCC_AHBPeriph_GPIOB
#define PIN_SPI_SCK         GPIO_Pin_3

#define GPIO_PORT_SPI_MOSI  GPIOB
#define RCC_SPI_MOSI        RCC_AHBPeriph_GPIOB
#define PIN_SPI_MOSI        GPIO_Pin_5

#define GPIO_PORT_SPI_MISO  GPIOB
#define RCC_SPI_MISO        RCC_AHBPeriph_GPIOB
#define PIN_SPI_MISO        GPIO_Pin_4

static struct spi_bus stm32_spi;
static struct spi_device bitbang_device;

static void stm32_spi_set_cs(int is_on)
{
    if (is_on)
    {
        GPIO_ResetBits(GPIO_PORT_SPI_CS, PIN_SPI_CS);
    }
    else
    {
        GPIO_SetBits(GPIO_PORT_SPI_CS, PIN_SPI_CS);
    }
}
static void stm32_spi_set_sck(int is_on)
{
    if (is_on)
    {
        GPIO_SetBits(GPIO_PORT_SPI_SCK, PIN_SPI_SCK);
    }
    else
    {
        GPIO_ResetBits(GPIO_PORT_SPI_SCK, PIN_SPI_SCK);
    }
}
static void stm32_spi_set_mosi(int is_on)
{
    if (is_on)
    {
        GPIO_SetBits(GPIO_PORT_SPI_MOSI, PIN_SPI_MOSI);
    }
    else
    {
        GPIO_ResetBits(GPIO_PORT_SPI_MOSI, PIN_SPI_MOSI);
    }
}
static int stm32_spi_get_miso(void)
{
    return (int)GPIO_ReadInputDataBit(GPIO_PORT_SPI_MISO, PIN_SPI_MISO);
}


static const struct spi_bitbang_ops ops = 
{
    .setsck  = stm32_spi_set_sck,
    .setmosi = stm32_spi_set_mosi,
    .getmiso = stm32_spi_get_miso,

    .udelay  = board_udelay,
    .delay_us= 1,
};
static const struct spi_cs_ops cs_ops0 = 
{
    .active = stm32_spi_set_cs,
};

static void RCC_Configuration(void)
{
    RCC_APB2PeriphClockCmd(RCC_SPI_CS | RCC_SPI_SCK | RCC_SPI_MOSI | RCC_SPI_MISO, ENABLE);
}

static void GPIO_Configuration(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    /* config SCL PIN */
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_InitStructure.GPIO_Pin = PIN_SPI_CS;
    GPIO_Init(GPIO_PORT_SPI_CS, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = PIN_SPI_SCK;
    GPIO_Init(GPIO_PORT_SPI_SCK, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = PIN_SPI_MOSI;
    GPIO_Init(GPIO_PORT_SPI_MOSI, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_Pin = PIN_SPI_MISO;
    GPIO_Init(GPIO_PORT_SPI_MISO, &GPIO_InitStructure);
}

int hw_spi_bitbang_init(void)
{
    RCC_Configuration();
    GPIO_Configuration();

    spi_bit_add_bus(&stm32_spi, "spib", &ops);

    spi_bus_attach_device(&bitbang_device, "spib0", "spib", (void *)&cs_ops0);

    return 0;
}
#endif
